<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="favicon.ico">

    <title>Microsoft AI for Earth - Land cover mapping platform</title>

    <!-- Core CSS -->
    <link href="css/leaflet.css" rel="stylesheet" />
    <link href="css/leaflet-slider.css" rel="stylesheet" />
    <link href="css/leaflet-sidebar.css" rel="stylesheet" />
    <link href="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.css" rel="stylesheet" />
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet-easybutton@2/src/easy-button.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.14/leaflet.draw.css">
    <link href="css/noty.css" rel="stylesheet">

    <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet">
    <link href="css/main.css" rel="stylesheet">
    

</head>

<body>

    <div id="map"></div>

    <div id="privacy" class="leaflet-container">
        <a href="https://privacy.microsoft.com/en-US/privacystatement" target="_blank">Privacy Statement</a>
    </div>
    
    <div id="sidebar" class="sidebar">
    
        <!-- Tab panes -->
        <div class="sidebar-content">

            <!-- Start of "home" tab -->
            <div class="sidebar-pane" id="home">
                <div style="text-align: center; margin-bottom:10px;" id="inputImages">
<!--                    <h3 id="lblModelInput">Model Input</h3>  -->
                    <img id="inputImage">
                    <div style="display:inline-block" id="exampleImages"><div style="display:inline-block" id="exampleImageList"></div></div>
                </div>
<!--
                <div style="text-align: center; margin-bottom:10px; width:100%;" id="exampleImages">
                    <h3>Land Cover Predictions</h3>
                    <div id="exampleImageList">
                    </div>
                </div>
-->
                <div style="display:none;text-align: left; margin-bottom:10px; width:100%; padding-left:30px;">
                    <span>Name of zone: <span id="lblZoneName">none selected</span></span>
                </div>

                <div style="margin-bottom:10px;">

                    <h3 style="display:none;text-align: center; margin-top:20px;">Correction type:</h3>
                    <div style="padding-left:20px">
                        <div id="classList"></div>
                        <div style="text-align: center; margin-top:10px; margin-bottom:20px;">
                            <button id="btnNewClass" style="background-color: gray; border-color: white;"> Add new class</button>
                        </div>

                        <div style="text-align: center; margin-top:10px;">
                            <button id="btnRetrain">Retrain (<span id="label-retrains">0</span> times)</button>
                        </div>
                        <div style="text-align: center; margin-top:10px;">
                            <button id="btnUndo">Undo</button>
                        </div>
                        <div style="text-align: center; margin-top:10px;">
                            <button id="btnReset">Reset</button>
                        </div>
                        <div style="text-align: center; margin-top:10px;">
                            <button id="btnDownload">Download</button>
                        </div>

                        <div style="text-align: center; margin-top:10px;">
                            <button id="btnCheckpoint">Create Checkpoint</button>
                        </div>

                        <div style="text-align: center; margin-top:5px;">
                            <div id="lblPNG"></div>
                            <div id="lblTIFF"></div>
                            <div id="lblStatistics"></div>
                        </div>

                        <div style="text-align: center; margin-top:10px;">
                            <button id="btnKillSession">End Session</button>
                        </div>
                    </div>
                </div>
            </div>
            <!-- End of "home" tab -->
        </div>
    </div>

    <!-- Core JavaScript
    ================================================== -->
    <script src="js/jquery-3.3.1.min.js"></script>
    <script src="js/noty.js" type="text/javascript"></script>
    <script src="js/jscolor.js" type="text/javascript"></script>

    <!-- Leaflet JavaScript
    ================================================== -->
    <script src="js/leaflet.js" type="text/javascript"></script>
    <script src="js/leaflet-slider.js" type="text/javascript"></script>
    <script src="js/leaflet-sidebar.min.js" type="text/javascript"></script>
    <script src="js/leaflet.filelayer.js" type="text/javascript"></script>
    <script src="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.js" type="text/javascript"></script>
    <script src="https://cdn.jsdelivr.net/npm/leaflet-easybutton@2/src/easy-button.js" type="text/javascript"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.14/leaflet.draw.js" type="text/javascript"></script>

    <!-- Application JavaScript
    ================================================== -->
    <script src="js/components.js" type="text/javascript"></script>
    <script src="js/handlers.js" type="text/javascript"></script>
    <script src="js/main.js" type="text/javascript"></script>
    <script src="js/utils.js" type="text/javascript"></script>
    <script src="js/globals.js" type="text/javascript"></script>

    <!-- List of backend URLS to query
    ================================================== -->
    <script src="endpoints.mine.js" type="text/javascript"></script>

    <script type="text/javascript">
        
        var zonePickerControl;
        //----------------------------------------------------------------------
        // Runtime entrance
        //----------------------------------------------------------------------
        $(document).ready(function(){

            //----------------------------------------------------------------------
            // Parse URL arguments
            //----------------------------------------------------------------------
            var args = getURLArguments()
            gBackendURL = SERVERS[args.backendID]["url"];
            gCurrentDataset = args.dataset;
            gCurrentModel = args.model;
            gCurrentCheckpoint = args.checkpoint;


            if(gCurrentCheckpoint === null || gCurrentCheckpoint === "-1"){
                console.debug("New checkpoint, not loading anything");
                loadClasses(MODELS[gCurrentModel]["classes"]);
            } else{
                loadClasses(CHECKPOINTS[gCurrentCheckpoint]["classes"]);
            }


            //----------------------------------------------------------------------
            // Load the dataset specific shapes
            //----------------------------------------------------------------------
            // TODO: This needs to be refactored out of main() somehow. e.g. If I want to create a new interface that handles zone clicks differently then it should be easy to do, while currently I would have to break everything about how zones are currently handled.
            if(DATASETS[gCurrentDataset]["shapeLayers"] !== null  && DATASETS[gCurrentDataset]["shapeLayers"].length !== 0){
                for(zoneSetId in DATASETS[gCurrentDataset]["shapeLayers"]){
                    // for each shapeLayer in the current dataset we need to load the GeoJSON in `zoneMaps`

                    var zoneName = DATASETS[gCurrentDataset]["shapeLayers"][zoneSetId]["name"];
                    gZoneMapsWeight[zoneName] = DEFAULT_ZONE_LINE_WEIGHTS[zoneSetId];
                    gZonemaps[zoneName] = L.geoJSON(null, {
                        style: DEFAULT_ZONE_STYLE(gZoneMapsWeight[zoneName]),
                        onEachFeature: forEachFeatureOnClick,
                        pane: "polygons"
                    });
                    
                    getZoneMap(zoneSetId, zoneName, DATASETS[gCurrentDataset]["shapeLayers"][zoneSetId]["shapesFn"]);
                }
            }

            //----------------------------------------------------------------------
            // Update the correction pixel size to the resolution of the dataset
            //----------------------------------------------------------------------
            CORRECTION_WINDOW_SIZE = DATASETS[gCurrentDataset]["dataLayer"]["resolution"];


            //----------------------------------------------------------------------
            // Setup map layers
            //----------------------------------------------------------------------

            // Create the basemap for the current dataset
            var baseLayer = L.tileLayer(DATASETS[gCurrentDataset]["basemapLayers"][0]["url"], DATASETS[gCurrentDataset]["basemapLayers"][0]["args"]);
            
            // This is the list of basemaps that will be displayed on the control in bottom left of GUI
            gCurrentBasemapLayerName = DATASETS[gCurrentDataset]["basemapLayers"][0]["layerName"];

            gBasemaps[gCurrentBasemapLayerName] = baseLayer;
            for(var i=1; i<DATASETS[gCurrentDataset]["basemapLayers"].length; i++){
                var layerName = DATASETS[gCurrentDataset]["basemapLayers"][i]["layerName"];
                var layer = L.tileLayer(DATASETS[gCurrentDataset]["basemapLayers"][i]["url"], DATASETS[gCurrentDataset]["basemapLayers"][i]["args"])
                gBasemaps[layerName] = layer;
            }
            gBasemaps["OpenStreetMap"] = getOSMLayer();
            gBasemaps["ESRI World Imagery"] = getESRILayer();


            // Setup the initial layers to be displayed on the map. This consists of the basemap from the dataset and, if defined, the first shape layer.
            var initialLayers = [baseLayer];
            if(DATASETS[gCurrentDataset]["shapeLayers"] !== null && DATASETS[gCurrentDataset]["shapeLayers"].length !== 0){
                initialLayers.push(gZonemaps[DATASETS[gCurrentDataset]["shapeLayers"][0]["name"]]);
                gCurrentZoneLayerName = DATASETS[gCurrentDataset]["shapeLayers"][0]["name"];
            }

            // Setup the global map object
            gMap = L.map('map', {
                zoomControl: false,
                crs: L.CRS.EPSG3857, // this is the projection CRS (EPSG:3857), but it is different than the data CRS (EPSG:4326). See https://gis.stackexchange.com/questions/225765/leaflet-map-crs-is-3857-but-coordinates-4326/225786.
                center: DATASETS[gCurrentDataset]["basemapLayers"][0]["initialLocation"],
                zoom: DATASETS[gCurrentDataset]["basemapLayers"][0]["initialZoom"],
                keyboard: false,
                minZoom: baseLayer.options.minZoom,
                layers: initialLayers
            });
            gMap.createPane('customPolygons');
            gMap.getPane('customPolygons').style.zIndex = 2001;

            gMap.createPane('polygons');
            gMap.getPane('polygons').style.zIndex = 2000;

            gMap.createPane('labels');
            gMap.getPane('labels').style.zIndex = 201;

            gMap.createPane('downloadOutput');
            gMap.getPane('downloadOutput').style.zIndex = 200;



            //----------------------------------------------------------------------
            // Create UI components. These are all defined in `js/components.js`.
            //----------------------------------------------------------------------
            addCustomLogoControl();
            addZoomControls();
            addDrawControls();
            var basemapPickerControl = addBasemapPickerControl(gBasemaps);
            var basemapPickerControlContainer = basemapPickerControl.getContainer();
            
            zonePickerControl = addZonePickerControl(gZonemaps);
            var zonePickerControlContainer = zonePickerControl.getContainer();
            
            var opacitySlider = addOpacitySlider();
            addInferenceWindowSizeSlider();
            // addCorrectionWindowSizeSlider();
            // addSharpnessToggleSlider();

            addSideBar();


            var uploadControl = addUploadControl();
            uploadControl.loader.on('data:loaded', function (e) {
                var zoneName = e.filename;

                if(zoneName in gZonemaps){ // if there is an entry in gZonemaps with the same filename then we have already loaded this file
                    console.debug("Error, already loaded this file");
                }else{
                    if(gCurrentZoneLayerName !== null){
                        console.debug("Removing existing zone layer");
                        gMap.removeLayer(gZonemaps[gCurrentZoneLayerName]);
                    }
                    gZoneMapsWeight[zoneName] = 3;
                    gZonemaps[zoneName] = e.layer;
                    e.layer.addTo(gMap);
                    zonePickerControl.addBaseLayer(e.layer, zoneName);
                }
            });
            uploadControl.loader.on('data:error', function (error) {
                console.error(error); //TODO: alert a reasonable error message
            });

            //----------------------------------------------------------------------
            // Register handlers. These are all defined in `js/handlers.js`
            //----------------------------------------------------------------------
            
            addInferenceMouseHandlers();
            addDrawControlHandlers();
            addOpacityKeyHandlers(opacitySlider);
            addRetrainKeyHandler();
            addGUIKeyHandlers();
            

            // $(zonePickerControlContainer).find('input[type=radio]').change(function() {
            //     var name = $(this).siblings()[0].innerHTML.trim();
            //     gCurrentZoneLayerName = name;
            //     console.debug("Switched zone layer to: " + name);
            // });

            // $(basemapPickerControlContainer).find('input[type=radio]').change(function() {
            //     var name = $(this).siblings()[0].innerHTML.trim();
            //     gCurrentBasemapLayerName = name;
            //     console.debug("Switched basemap layer to: " + name);
            // });

            gMap.on('baselayerchange', function(e) {
                //https://gis.stackexchange.com/questions/171911/getting-current-layer-in-control-event-of-leaflet
                console.log(e);
            });

            $("#btnRetrain").click(doRetrain);
            $("#btnUndo").click(doUndo);
            $("#btnReset").click(doReset);
            $("#btnDownload").click(doDownloadTile);
            $("#btnCheckpoint").click(doCreateCheckpoint)

            $("#btnKillSession").click(doKillSession)


            $("#btnNewClass").click(function(){
                
                var newClassIdx = CLASSES.length;
                var newClassName = "Class " + (newClassIdx + 1);
                var newColor = getRandomColor();

                var newClassElement =  $("<div class='radio'>");
                var newLabel = $(" \
                    <label><input type='radio' name='radClasses' class='radClasses' value='"+newClassName+"'><span class='className'>"+newClassName+"</span> (<span class='classCounts'>0</span> samples since last retrain)<i class='fa fa-edit ml-1 classNameEdit'></i></label> \
                ");

                var newPicker = document.createElement('button');
                newPicker.classList.add("circle");
                newPicker.classList.add("jscolor");
                newPicker.setAttribute("data-class-label", newClassName);
                newPicker.setAttribute("data-class-idx", newClassIdx);
                var output = new jscolor(newPicker, {
                    valueElement: null,
                    value: newColor.substr(1),
                    position:'left',
                    zIndex:2001,
                    closable:true,
                    closeText:'Close',
                    onFineChange:'updateClassColor(this)'
                });

                newClassElement.append(newPicker);
                newClassElement.append(newLabel);        
            
                $("#classList").append(newClassElement);

                CLASSES.push({
                    "name": newClassName,
                    "color": newColor,
                    "count": 0
                });
            });

            //----------------------------------------------------------------------
            // Setup radio button change detection
            //----------------------------------------------------------------------
            $(document).on('change', '.radClasses', function(){

                $('.radio label').removeClass("selected");
                $(this).parent().addClass("selected");

                gSelectedClassIdx = findClassByName(this.value);
            });

            $(document).on('click', '.classNameEdit', function(){
                var oldName = $(this).siblings(".className").html();
                var newName = prompt("New label name for '"+oldName+"'");
                $(this).siblings(".className").html(newName);
                $(this).siblings(".radClasses").val(newName);
                
                $(this).parent().siblings(".jscolor").attr("data-class-name", newName);

                var classIdx = findClassByName(oldName);
                console.debug(classIdx);
                CLASSES[classIdx]["name"] = newName;
            });
            
            //----------------------------------------------------------------------
            // Setup the example images list
            //----------------------------------------------------------------------
            
            //for(var i=0; i<SERVERS.length; i++){
            for(var i=0; i<1; i++){
                var img = $("<img class='exampleImage'>");
                img.attr("im-id", i);
                img.attr("id", "exampleImage_"+i);
                $("#exampleImageList").append(img);
            }

            $(".exampleImage").click(function(){
                $(".exampleImage").removeClass("active");
                $(this).addClass("active");
                
                var idx = gCurrentPatches.length-1;
                gActiveImgIdx = $(this).attr("im-id");

                var srcs = gCurrentPatches[idx]["patches"][gActiveImgIdx]["srcs"];
                let tSelection = gDisplayHard ? "hard" : "soft";
                gCurrentPatches[idx]["imageLayer"].setUrl(srcs[tSelection]);
                gCurrentPatches[idx]["activeImgIdx"] = gActiveImgIdx;
                $(this).attr("src", srcs[tSelection]);
            });

        });

    </script>
</body>

</html>
